<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta http-equiv="Cache-Control" content="no-siteapp">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=1, minimum-scale=1, maximum-scale=1">
<meta name="renderer" content="webkit">
<meta name="google" value="notranslate">
<meta name="robots" content="index,follow">


<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Akkuman">
<meta name="twitter:description" content="Akkuman的技术博客">
<meta name="twitter:image:src" content="http://127.0.0.1:8000/images/avatar.png">

<meta property="og:url" content="http://127.0.0.1:8000">
<meta property="og:title" content="Akkuman">
<meta property="og:description" content="Akkuman的技术博客">
<meta property="og:site_name" content="Akkuman">
<meta property="og:image" content="http://127.0.0.1:8000/images/avatar.png">
<meta property="og:type" content="website">
<meta name="robots" content="noodp">

<meta itemprop="name" content="Akkuman">
<meta itemprop="description" content="Akkuman的技术博客">
<meta itemprop="image" content="http://127.0.0.1:8000/images/avatar.png">

<link rel="canonical" href="http://127.0.0.1:8000">

<link rel="shortcut icon" href="/favicon.png">
<link rel="apple-itouch-icon" href="/favicon.png">

<link type="text/css" rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/4.0.0/css/bootstrap.min.css">
<link type="text/css" rel="stylesheet" href="/bundle/css/prism.css">
<link type="text/css" rel="stylesheet" href="/bundle/css/zoom.css">
<link type="text/css" rel="stylesheet" href="/bundle/css/main.css">
<script src="https://cdn.bootcss.com/jquery/2.2.4/jquery.min.js"></script>



<script>var cPlayers = [];var cPlayerOptions = [];</script>


<script type="text/javascript">
    var timeSinceLang = {
        year: '年前',
        month: '个月前',
        day: '天前',
        hour: '小时前',
        minute: '分钟前',
        second: '秒前'
    };
    var root = '';
</script>


        <meta name="keywords" content="Python,life,">
        <meta name="description" content="javbus爬虫-老司机你值得拥有">
        <meta name="author" content="Akkuman">
        <title>javbus爬虫-老司机你值得拥有</title>
    </head>
    <body>
        
        <header id="header" class="clearfix">
  <div class="container-fluid">
      <div class="row">
          <div class="logo">
              <div class="header-logo">
                <script>
                  var getwbclass = function() {
                    var wbclass = ['b', 'w'];
                    return wbclass[Math.floor(Math.random()*wbclass.length)];
                  }
                  var sitetitle = "Akkuman";
                  for (i in sitetitle) {
                    document.write('<a href="/"><span class="' + getwbclass() + ' titlechar">' + sitetitle.charAt(i) + '</span></a>');
                  }          
                  
                </script>
                
                <a id="btn-menu" href="javascript:isMenu();">
                    <span class="b">·</span>
                </a>
                <a href="javascript:isMenu1();">
                    <span id="menu-1" class="bf">1</span>
                </a>
                <a href="javascript:isMenu2();">
                    <span id="menu-2" class="bf">2</span>
                </a>
                <a href="javascript:isMenu3();">
                    <span id="menu-3" class="bf">3</span>
                </a>
              </div>
              <div id="menu-page">
                <a href="/archive.html"><li>归档</li></a>
                <a href="/tag.html"><li>标签</li></a>
                
                <a href="/atom.xml"><li>订阅</li></a>
                
                <a href="about.html"><li>关于</li></a>
              </div>
              <div id="search-box">
                  <div id="search">
                      <input autocomplete="off" type="text" name="s" id="menu-search" placeholder="搜索..." data-root="" />
                  </div>
              </div>
          </div>
      </div>
  </div>
  </header>
        <div id="body" class="clearfix">
            <div class="container-fluid">
                <div class="row">
                    <div id="main" class="col-12 clearfix" role="main">
                        <article class="posti" itemscope itemtype="http://schema.org/BlogPosting">
                            <h1 class="post-title" itemprop="name headline">javbus爬虫-老司机你值得拥有</h1>
                            <div class="post-meta">
                                <p>
                                    Written by <a itemprop="name" href="/about.me.html" rel="author">Akkuman</a> with ♥ on <time datetime="1481019713" itemprop="datePublished"></time> in <a href="/tag/Python/index.html">Python </a><a href="/tag/life/index.html">life </a>
                                </p>
                            </div>
                            <div class="post-content" itemprop="articleBody">
                                <hr />

<h1>起因</h1>

<hr />

<p>有个朋友叫我帮忙写个爬虫，爬取javbus5上面所有的详情页链接，也就是所有的<a href="https://www.javbus5.com/SRS-055这种链接，">https://www.javbus5.com/SRS-055这种链接，</a>
我一看，嘿呀，这是司机的活儿啊，我绝对不能辱没我老司机的名声（被败坏了可不好），于是开始着手写了</p>

<hr />

<h1>构思</h1>

<hr />

<ul>
<li>爬虫调度启动程序crawler.py</li>
<li>页面下载程序downloader.py</li>
<li>页面解析程序pageparser.py</li>
<li>数据库入库与去重管理程序controler.py</li>
</ul>

<p>爬取入口为第一页，当页面中存在下一页的超链接继续往下爬，这是个死循环，跳出条件为没有了下一页的链接</p>

<p>在某一页中解析页面，返回所有的详情页链接，利用迭代器返回，然后在主程序中调用解析程序对页面信息进行解析并包装成字典返回，其中用详情页网址作为数据库主键，其他信息依次写入数据库</p>

<p>当这一页所有的子链接爬取完成后，继续爬取下一页。</p>

<p>将数据存入数据库，用的是sqllite3,失败的网址页存入一个fail_url.txt。</p>

<p>对于增量爬取，我是这么做的，当爬取到相同的网址时结束程序，这么做也有漏洞，才疏学浅，我没想到太好的办法，希望有好办法的给我说一声（布隆过滤正在研究之中），如果用数据库查询去重，那么势必导致二次爬取，我们都知道，爬虫更多的时间是花在网络等待上</p>

<hr />

<h1>问题</h1>

<hr />

<p>在写爬虫的过程中遇到了一些问题</p>

<ol>
<li><p>在墙内爬不动，爬取几个之后就失败，这个解决方案只需要全局翻墙爬取就可以了</p></li>

<li><p>本来之前加了多线程并发爬取，但是发现爬取一段时间后会封ip导致整体无法运行，本来想搞个代理池进行并发，结果网上免费的代理太慢太慢，根本打不开网页，于是就改回了单线程</p></li>

<li><p>就是我的那个不完善的增量爬取，导致了你一次爬取就需要爬取完成，不然数据库里面存在你之前爬到的，爬取到你已有的会直接停止</p></li>

<li><p>存在反扒策略
详情页中的磁力链接是ajax动态加载的，通过分析抓包，可以在XHR中找到是一个get请求，至于参数，我开始不知道怎么得来的，后来在html代码中找到了，我放几张图大家就明白了
<img src="" data-src="http://7xusrl.com1.z0.glb.clouddn.com/javbus_001.jpg" alt="1" /></p></li>
</ol>

<p>我们通过对响应内容的查看可以发现磁力的加载访问了类似于这样一个网址</p>

<pre><code>   https://www.javbus5.com/ajax/uncledatoolsbyajax.php?gid=30100637207&amp;lang=zh&amp;img=https://pics.javbus.info/cover/59pc_b.jpg&amp;uc=0&amp;floor=921
</code></pre>

<p>那么这些get参数是从哪里来呢，这就是通过经验与基本功去发现了</p>

<p>通过对html源文件的搜索，我们即可直接发现答案
   <img src="" data-src="http://7xusrl.com1.z0.glb.clouddn.com/javbus_003.png" alt="3" />
   <img src="" data-src="http://7xusrl.com1.z0.glb.clouddn.com/javbus_004.png" alt="4" />
   通过分析发现，后面的floor是个随机数参数，一般这种参数可以去除无影响，事实也是这样</p>

<p>我利用HttpRequest模拟发包，对这个请求直接get，发现所有数据隐藏
   <img src="" data-src="http://7xusrl.com1.z0.glb.clouddn.com/javbus_002.png" alt="2" /></p>

<p>那么肯定是有反扒的策略，伪造请求头，反扒也就那么几种，通过分析发现是同源策略，对Referer请求头伪造成来源网址就可以直接获取到内容了
   <img src="" data-src="http://7xusrl.com1.z0.glb.clouddn.com/javbus_005.png" alt="5" />
   <img src="" data-src="http://7xusrl.com1.z0.glb.clouddn.com/javbus_006.jpg" alt="6" />
   <img src="" data-src="http://7xusrl.com1.z0.glb.clouddn.com/javbus_007.png" alt="7" /></p>

<ol>
<li><p>常见的Python2.x编码问题,全部转换为unicode字节流就可以了
这个问题在我博客中已经记录了<a href="http://www.53xiaoshuo.com/Python/77.html">http://www.53xiaoshuo.com/Python/77.html</a>
有兴趣的童鞋可以看看</p></li>

<li><p>遇到的最闹心问题是详情页的项目抓取，有的详情页的类别不同，我开始只分析了一个页面，导致写的规则在有的页面上频频出错
导致后面对抓取规则进行了大改,重写了分析规则，用了个笨办法，毕竟那小块的html写的十分不规范，正则规则有三种，挺烦人
<img src="" data-src="http://7xusrl.com1.z0.glb.clouddn.com/javbus_008.png" alt="8" />
<img src="" data-src="http://7xusrl.com1.z0.glb.clouddn.com/javbus_009.jpg" alt="9" />
比如上图的两个就不同，html代码更是稀烂，需要判断有没有这个项，没有就设置空字节入库</p></li>
</ol>

<p>在这其中纠结了一个问题
   <img src="" data-src="http://7xusrl.com1.z0.glb.clouddn.com/javbus_010.png" alt="10" /></p>

<p>就是对于这两种的比较，我想上面这种变成下面这种，毕竟第一种的话，soup.find要执行两次，但是下面这种又要比上面那个多一行，丑一点
   最后我选择了第二种，所有的信息分析代码就不贴了，具体想看的直接看我的代码文件就好了</p>

<hr />

<h1>小Tips</h1>

<hr />

<ol>
<li><p>对于动态加载的内容的爬取，能不用selenium去模拟浏览器爬取就不用，耗费资源，更好的是自己分析网络请求，然后构造</p></li>

<li><p>对于页面信息的解析，要多看几个页面，看是否相同，别到时候做多事情</p></li>

<li><p>多看别人的博客学习思路</p></li>
</ol>

<hr />

<h1>注意</h1>

<hr />

<p>爬虫依赖的第三方库有Requests，BeautifulSoup，使用前请先pip install这两个第三方库</p>

<hr />

<h1>测试展与地址</h1>

<hr />

<p><img src="" data-src="http://7xusrl.com1.z0.glb.clouddn.com/javbus_011.jpg" alt="11" />
<img src="" data-src="http://7xusrl.com1.z0.glb.clouddn.com/javbus_012.jpg" alt="12" /></p>

<hr />

<h2>代码地址:</h2>

<hr />

<ul>
<li><em>coding.net</em>    <a href="https://coding.net/u/Akkuman/p/Javbus_crawler">javbus_crawler</a></li>
<li><em>github.com</em>    <a href="https://github.com/akkuman/Javbus_crawler">javbus_crawler</a></li>
</ul>

<p>司机的名声总算是没有辱没，秋名山依旧，嘿嘿
<img src="" data-src="https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=2070695546,2193961465&amp;fm=116&amp;gp=0.jpg" alt="13" /></p>

<p><strong>转载请注明来源作者</strong>
 - 博客：53xiaoshuo.com | hacktech.cn
 - 作者：Akkuman</p>

                            </div>
                            <div style="display:block;" class="clearfix">
                                <section style="float:left;">
                                    <span itemprop="keywords" class="tags">
                                        tag(s): <a href="/tag/Python/index.html">Python </a><a href="/tag/life/index.html">life </a>
                                    </span>
                                </section>
                                <section style="float:right;">
                                    <span><a id="btn-comments" href="javascript:isComments();">show comments</a></span> · <span><a href="javascript:goBack();">back</a></span> · 
                                    <span><a href="/">home</a></span>
                                </section>
                            </div>
                            



<div id="comments" class="gen">
    <script>
        document.write('<section id="disqus_thread"></section>');
        var site_comment_load = function disqus() {
            var d = document, s = d.createElement('script');
            s.src = '//Akkum4n.disqus.com/embed.js';
            s.setAttribute('data-timestamp', +new Date());
            (d.head || d.body).appendChild(s);
        }
    </script>
</div>

                        </article>
                    </div>
                </div>
            </div>
        </div>
        <footer id="footer" role="contentinfo">
    <div class="container-fluid">
        <div class="row">
        <div class="col-12">
            &copy; 
            <script type="text/javascript">
                document.write(new Date().getFullYear());
            </script>
            <a href="/">Akkuman</a>.
            Using <a target="_blank" href="http://www.chole.io/">Ink</a> & <a target="_blank" href="/">Story</a>.
        </div>
        </div>
    </div>
</footer>

<script src="https://cdn.bootcss.com/jquery/2.2.4/jquery.min.js"></script>
<script src="/bundle/js/prism.js"></script>
<script src="/bundle/js/zoom-vanilla.min.js"></script>
<script src="/bundle/js/main.js"></script>

<script>
    window.onload=function(){
        if (window.location.hash!='') {
          var i=window.location.hash.indexOf('#comment');
          var ii=window.location.hash.indexOf('#respond-post');
          if (i != '-1' || ii != '-1') {
            document.getElementById('btn-comments').innerText='hide comments';
            document.getElementById('comments').style.display='block';
          }
        }
    }

    function isMenu(){
        if(document.getElementById('menu-1').style.display=='inline'||document.getElementById('menu-1').style.display=='block'){
            $('#search-box').fadeOut(200);
            $('#menu-page').fadeOut(200);
            $('#menu-1').fadeOut(500);
            $('#menu-2').fadeOut(400);
            $('#menu-3').fadeOut(300);
        } else {
            $('#menu-1').fadeIn(150);
            $('#menu-2').fadeIn(150);
            $('#menu-3').fadeIn(150);
        }
    }

    function isMenu1(){
        if(document.getElementById('menu-page').style.display=='block'){
            $('#menu-page').fadeOut(300);
        } else {
            $('#menu-page').fadeIn(300);
        }
    }

    function isMenu2(){
        if(document.getElementById('torTree')){
            if(document.getElementById('torTree').style.display=='block'){
                $('#torTree').fadeOut(300);
            } else {
                $('#torTree').fadeIn(300);
            }
        }
    }

    function isMenu3(){
        if(document.getElementById('search-box').style.display=='block'){
            $('#search-box').fadeOut(300);
        } else {
            $('#search-box').fadeIn(300);
        }
    }

    function isComments(){
        if(document.getElementById('btn-comments').innerText=='show comments'){
            document.getElementById('btn-comments').innerText='hide comments';
            document.getElementById('comments').style.display='block';
            site_comment_load();
        } else {
            document.getElementById('btn-comments').innerText='show comments';
            document.getElementById('comments').style.display='none';
        }
    }

    function Search404(){
        $('#menu-1').fadeIn(150);
        $('#menu-2').fadeIn(150);
        $('#menu-3').fadeIn(150);
        $('#search-box').fadeIn(300);
    }

    function goBack(){
        window.history.back();
    }
</script>


<script async>
"use strict";
(function(){
var cp = function(){
    var len = cPlayerOptions.length;
    for(var i=0;i<len;i++){
        var element = document.getElementById('player' + cPlayerOptions[i]['id'])
        while (element.hasChildNodes()) {
            element.removeChild(element.firstChild);
        };
        cPlayers[i] = new cPlayer({
            element: element,
            list: cPlayerOptions[i]['list'],
            });
    };
    cPlayers = [];cPlayerOptions = [];
};
var script = document.createElement('script');
script.type = "text/javascript";
script.src = "https://cdn.bootcss.com/cplayer/3.2.1/cplayer.js";
script.async = true;
if(script.readyState){  
    script.onreadystatechange = function(){
        if (script.readyState == "loaded" ||
            script.readyState == "complete"){
            script.onreadystatechange = null;
            cp();
        }
    };
}else{  
    script.onload = function(){
        cp();
    };
}
document.head.appendChild(script);
})();
</script>

    </body>
</html>
